package com.tianji.learning.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Wrapper;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author liuchun
 * @since 2024-06-30
 */
@Service
@RequiredArgsConstructor
@Slf4j
@SuppressWarnings("all")
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {


    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    private final LearningRecordMapper recordMapper;

    /**
     * 添加课程到课表
     * @param userId
     * @param courseIds
     */
    @Override
    @Transactional
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //根据课程id集合批量查询课程信息
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(cInfoList)){
            log.info("课程信息不存在");
            return;
        }
        List<LearningLesson> learningLessonList = new ArrayList<>();
        for (CourseSimpleInfoDTO cInfo : cInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(cInfo.getId());
            learningLesson.setExpireTime(LocalDateTime.now().plusMonths(cInfo.getValidDuration()));
            learningLessonList.add(learningLesson);
        }
        //批量新增
        saveBatch(learningLessonList);
    }

    /**
     * 分页查询我的课表
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryLessons(PageQuery pageQuery) {
        //获取当前用户
        Long userId = UserContext.getUser();
        //分页查询
        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId).page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //查询课程信息
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if(CollUtils.isEmpty(cInfoList)){
            return PageDTO.empty(page);
        }
        //转换为Map
        Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //循环便利封装vo返回
        List<LearningLessonVO> list = new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            LearningLessonVO vo = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO cInfo = cMap.get(record.getCourseId());
            vo.setCourseName(cInfo.getName());
            vo.setCourseCoverUrl(cInfo.getCoverUrl());
            vo.setSections(cInfo.getSectionNum());
            list.add(vo);
        }
        return PageDTO.of(page,list);
    }

    /**
     * 查询正在学习的课程
     * @return
     */
    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        //获取当前用户
        Long userId = UserContext.getUser();
        if (userId == null){
            return null;
        }
        //查询当前用户最近学习的课程
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null){
            return null;
        }
        //远程调用课程服务，给vo中的课程名 封面 章节数赋值
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null){
            throw  new BadRequestException("课程不存在!");
        }
        vo.setCourseName(cInfo.getName());
        vo.setSections(cInfo.getSectionNum());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());

        //统计课表中课程总数
        Integer count = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        vo.setCourseAmount(count);
        //通过远程调用课程微服务，获取小节名称和小节编号
        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getCourseId()));
        if (!CollUtils.isEmpty(cataInfos)){
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionName(cataInfo.getName());
            vo.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return vo;
    }

    /**
     * 检查课程是否有效
     * @param courseId
     * @return
     */
    @Override
    public Long checkValid(Long courseId) {
        //获取当前用户
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery().eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId).one();
        if (lesson == null){
            return null;
        }
        LocalDateTime now = LocalDateTime.now();
        if (lesson.getExpireTime() != null && now.isBefore(lesson.getExpireTime())){
            return null;
        }
        return lesson.getId();
    }

    /**
     * 查询用户课表中指定课程状态
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryLessonById(Long courseId) {
        //获取用户id
        Long userId = UserContext.getUser();
        if (userId == null){
            throw new BizIllegalException("用户信息为空!");
        }
        LearningLesson lesson = lambdaQuery().eq(LearningLesson::getUserId, userId).eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null){
            throw new BadRequestException("课程信息不存在!");
        }
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        return vo;
    }

    /**
     * 创建学习计划
     * @param learningPlanDTO
     */
    @Override
    public void createLearningPlans(LearningPlanDTO learningPlanDTO) {
        //获取当前用户
        Long userId = UserContext.getUser();
        if (userId == null){
            throw new BizIllegalException("用户未登录");
        }
        boolean success = this.lambdaUpdate()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, learningPlanDTO.getCourseId())
                .set(LearningLesson::getWeekFreq, learningPlanDTO.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .update();
        if (!success){
            throw new DbException("创建学习计划失败!");
        }
    }

    /**
     * 查询学习计划进度
     * @param pageQuery
     * @return
     */
    @Override
    public LearningPlanPageVO queryLearningPlans(PageQuery pageQuery) {
        //获取当前用户
        Long userId = UserContext.getUser();
        //获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime beginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime endTime = DateUtils.getWeekEndTime(now);
        //todo 查询积分
        //查询本周学习计划总数据(这里利用wrapper实现统计)
        QueryWrapper<LearningLesson> wrapper = new QueryWrapper();
        wrapper.select("sum(week_freq) as plansTotal");
        wrapper.eq("user_id", userId);
        wrapper.eq("plan_status",PlanStatus.PLAN_RUNNING);
        wrapper.in("status",LessonStatus.NOT_BEGIN,LessonStatus.LEARNING);
        Map<String, Object> map = this.getMap(wrapper);
        Integer plansTotal = 0;
        if (!map.isEmpty() && map.get("plansTotal") != null){
            plansTotal = Integer.valueOf(map.get("plansTotal").toString());
        }
        //查询本周 实际 已学习的计划总数据
        QueryWrapper<LearningRecord>  recordQueryWrapper = new QueryWrapper();
        recordQueryWrapper.between("finish_time",beginTime,endTime);
        recordQueryWrapper.eq("user_id", userId);
        recordQueryWrapper.eq("finished",true);
        Integer weekFinished = recordMapper.selectCount(recordQueryWrapper);

        //查询课表数据
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            LearningPlanPageVO vo = new LearningPlanPageVO();
            vo.setPages(0L);
            vo.setTotal(0L);
            vo.setList(CollUtils.emptyList());
            return vo;
        }
        //远程调用课程微服务 获取课程信息
        Set<Long> ids = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> cInfos = courseClient.getSimpleInfoList(ids);
        if (CollUtils.isEmpty(cInfos)){
            throw new BizIllegalException("课程信息不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cInfoMap = cInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //查询学习记录表 本周 当前用户下 每一门课下 已学习的小节数量
        QueryWrapper<LearningRecord> rWrapper = new QueryWrapper();
        rWrapper.select("lesson_id as lessonId","count(*) as userId");
        rWrapper.eq("user_id", userId);
        rWrapper.between("finish_time",beginTime,endTime);
        rWrapper.eq("finished",true);
        rWrapper.groupBy("lesson_id");
        List<LearningRecord> learningRecords = recordMapper.selectList(rWrapper);
        Map<Long, Long> courseWeekFinishedNumMap = learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId, c -> c.getUserId()));
        //封装vo返回
        LearningPlanPageVO vo = new LearningPlanPageVO();
        vo.setWeekTotalPlan(plansTotal);
        vo.setWeekFinished(weekFinished);
        List<LearningPlanVO> volist = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningPlanVO planVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            CourseSimpleInfoDTO cInfoDto = cInfoMap.get(record.getCourseId());

            planVO.setCourseName(cInfoDto.getName());
            planVO.setSections(cInfoDto.getSectionNum());
            planVO.setWeekLearnedSections(courseWeekFinishedNumMap.getOrDefault(record.getId(),0L).intValue());

            volist.add(planVO);
        }
        return vo.pageInfo(page.getTotal(),page.getPages(),volist);
    }

}
